package com.atguigu.hbase;

import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;

import java.io.IOException;

/**
 * Created by Smexy on 2022/6/21
 *
 *      作用：
 *              ①先创建一个客户端
 *              ②提供辅助方法，方便使用客户端对数据库进行操作
 *
 *       Connection:
 *              ①自动维护对集群以及zk的连接
 *              ②Connection可以从 ConnectionFactory中实例化
 *              ③特点:
 *                      重量级，不建议频繁创建。
 *                      线程安全，可以在多线程中共享。
 *
 *              ④Table:  负责对一张表的 DML(CRUD)操作
 *               Admin:   负责对标的DDL(建表，删表，列出表)操作
 *                      轻量级(创建简单)，不是线程安全，每个线程需要有自己的Table或Admin实例。
 *
 *              ⑤生命周期由调用者维护，谁创建，谁关闭
 *
 *      -------------------------------DML
 *          Table.get(Get get): 查询单行
 *          Table.put(Put get): 插入或更新。
 *                          tablename/rowkey/cf:cq/value
 *          Table.delete(Delete get): 删除
 *          Table.scan(Scan get): 扫描多行
 *
 *      ---------------------------工具类
 *        前提知识： HBase中没有数据类型，所有不同类型的数据，都是封装成统一的类型Byte[]
 *              Bytes.toBytes(T t): 将T类型转为 byte[]
 *              Byte.toXxx(Bytes []): 把byte[]还原为指定的Xxx类型
 *
 *              CellUtil:  用来处理每个Cell中的不同属性(rowkey,cf,cq,value,ts)
 *                     CellUtil.cloneXxx(xxx): 取出Cell中指定属性的 byte[]
 */
public class HBaseUtil {

    private Connection conn;

    {

        /*
            本质是调用HBaseConfiguration.create() 返回一个Configuration
                这个Configuration是hadoop包下的Configuration，在创建时，自动读取hadoop的默认配置文件。
                读完后，会继续读取hbase的配置文件

              客户端如何进行读写?
                    不管是读还是写，第一步都是去连接 zk

         */
        try {
            conn = ConnectionFactory.createConnection();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /*
            遍历Result(一行数据)
                一行有N个Cell组成
     */
    public void  parseResult(Result result){

        Cell[] cells = result.rawCells();

        for (Cell cell : cells) {

            System.out.println("--------------------");
            System.out.println("rowkey：" + Bytes.toString(CellUtil.cloneRow(cell)));
            System.out.println("cf:cq =>" + Bytes.toString(CellUtil.cloneFamily(cell)) + ":" + Bytes.toString(CellUtil.cloneQualifier(cell)));
            System.out.println("value：" + Bytes.toString(CellUtil.cloneValue(cell)));

        }

    }

    /*
            用来封装一个Put对象
     */
    public Put createPut(String rowkey,String cf,String cq,String value){

        //创建一个可以向某一行插入的Put对象
        Put put = new Put(Bytes.toBytes(rowkey));

        //向这一行中添加要插入的列
        put.addColumn(Bytes.toBytes(cf),Bytes.toBytes(cq),Bytes.toBytes(value));

        return put;

    }

    /*
            根据传入的表名，创建对应这张表的Table对象
     */
    public Table createTable(String tableName) throws IOException {

        /*
                先对表名进行校验，验证不是一个非法的字符串

                验证字符串是否是null,"",或 “白字符(空格，\t)”
         */
        if (StringUtils.isBlank(tableName)){

            throw new RuntimeException("表名非法!");
        }

        return conn.getTable(TableName.valueOf(tableName));

    }


    public void close() throws IOException {

        if (conn != null){

            conn.close();
        }

    }



}
